package com.gameShare.service.user

import com.gameShare.constances.ExpireTime
import com.gameShare.entity.dto.user.UserBaseInfoDto
import com.gameShare.entity.po.user.UserInfo
import com.gameShare.enums.misc.ResponseCodeEnum
import com.gameShare.exceptions.BusinessException
import com.gameShare.mappers.user.UserInfoMapper
import com.gameShare.service.misc.RedisService
import com.gameShare.utils.StringUtils
import jakarta.servlet.http.Cookie
import jakarta.servlet.http.HttpServletRequest
import jakarta.servlet.http.HttpServletResponse
import org.springframework.stereotype.Service
import org.springframework.web.context.request.RequestContextHolder
import org.springframework.web.context.request.ServletRequestAttributes
import java.time.LocalDateTime
import java.util.*

@Service
class AccountService(
    private val userInfoMapper : UserInfoMapper,
    private val redisService: RedisService,
    private val userActionService: UserActionService
) {

    companion object{
        const val TOKEN_KEY = "token"
        const val USER_ID_LENGTH = 10
    }

    /**
     * 登录并且将token放入cookie中
     *
     * @param loginInfo
     * @return
     */
    fun login(response: HttpServletResponse,request : HttpServletRequest, loginInfo: UserInfo): UserBaseInfoDto {
        val userInfo : UserBaseInfoDto = loginInfo.email?.let { userInfoMapper.selectBaseInfoByEmail(it) }
            ?: throw BusinessException(ResponseCodeEnum.ARGUMENT_ERROR.code, "账号不存在")
        loginInfo.password?.let {
            if(it != userInfo.password){
                throw BusinessException(ResponseCodeEnum.ARGUMENT_ERROR.code, "密码错误")
        } }
        loginInfo.password = ""
        userInfo.lastLoginTime = LocalDateTime.now()
        userInfo.lastLoginIp = getClientRequestIp()
        val oldToken = request.cookies
            ?.firstOrNull { it.name == "token" }
            ?.value

        oldToken?.let{
            redisService.delUserTokenInfo(oldToken)
        }
        val token = UUID.randomUUID().toString()
        redisService.saveUserTokenInfo(token, userInfo)
        saveTokenToCookie(response, token)
        return userInfo
    }

    /**
     * 注册服务
     * 检查邮箱是否存在若存在则抛出异常
     * @param
     */
    fun register(registerInfo: UserInfo){
        // TODO 对头像路径进行判断是否合法

        if (registerInfo.email?.let { userInfoMapper.selectByEmail(it) } != null){
            throw BusinessException(ResponseCodeEnum.INFO_EXIST.code, "邮箱已注册")
        }

        val userId : String = StringUtils.generateRandomUserId(USER_ID_LENGTH)
        registerInfo.id = userId
        registerInfo.lastLoginTime = LocalDateTime.now()
        registerInfo.lastLoginIp = getClientRequestIp()
        registerInfo.password = registerInfo.password?.let {
            if (!it.matches(Regex("^[a-zA-Z0-9_]+$"))) {
                throw BusinessException(ResponseCodeEnum.ARGUMENT_ERROR.code, "密码不符合规定")
            }
            StringUtils.Companion.md5(it)
        }
        registerInfo.joinTime = LocalDateTime.now()
        userActionService.createUserActionRecord(userId)
        userInfoMapper.insert(registerInfo)
    }

    /**
     * 获取用户ip
     *
     * @return 用户当前ip
     */
    private fun getClientRequestIp(): String {
        return (RequestContextHolder.getRequestAttributes() as ServletRequestAttributes)
            .request
            .remoteAddr
    }

    /**
     * 保存token至用户的cookie
     *
     * @param response 用户请求体
     * @param token 登录令牌
     */
    private fun saveTokenToCookie(response: HttpServletResponse, token : String){
        val cookie = Cookie(TOKEN_KEY, token)
        cookie.maxAge = ExpireTime.INT_SEC_ONE_DAY
        cookie.isHttpOnly = true
        response.addCookie(cookie)
    }

    fun checkUserAccountExist(userId : String){
        userInfoMapper.selectById(userId)
            ?: throw BusinessException(ResponseCodeEnum.ARGUMENT_ERROR)
    }


    // TODO 账号信息管理服务
}